#ifndef xpack_utils_temp_allocator
#define xpack_utils_temp_allocator
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::utils_temp_allocator::inc
#include"define/base_type.hpp"
#include"dumb/disable_copy.hpp"
#include"macro/xexport.hpp"
#include"macro/xstruct.hpp"
#include"utils/memory.hpp"
#pragma pop_macro("xuser")

namespace mixc::utils_temp_allocator{
    xstruct(
        xname(memory_item),
        xpubf(next, memory_item *),
        xpubf(bytes, uxx)
    ) $
}

namespace mixc::utils_temp_allocator::origin{
    xstruct(
        xname(temp_allocator),
        xpubb(inc::disable_copy),
        xprif(m_root, memory_item *),
        xprif(m_total_slice, uxx),
        xprif(m_used_bytes, uxx)
    )
    private:
        using mip_t             = memory_item *;
    public:
        xprops()
            xpubget(total_slice, uxx);
            xpubget(used_bytes, uxx);
            xpubgetx(real_bytes, uxx){
                xr{
                    return m_used_bytes + sizeof(memory_item) * m_total_slice;
                }
            };
        $

        xprops_operator()
    public:
        constexpr temp_allocator():
            m_root(nullptr), m_total_slice(0), m_used_bytes(0){
        }

        constexpr temp_allocator(the_t && self):
            m_root(self.m_root), m_total_slice(self.m_total_slice), m_used_bytes(self.m_used_bytes){

            self.m_root         = nullptr;
            self.m_total_slice  = 0;
            self.m_used_bytes   = 0;
        }

        ~temp_allocator(){
            this->clear();
        }

        the_t && hand_over() const {
            return (the_t &&)xthe;
        }

        voidp operator()(uxx bytes) const {
            auto item       = mip_t(inc::memory::default_alloc<void>(bytes + sizeof(memory_item)));
            item->bytes     = bytes + sizeof(memory_item);
            item->next      = m_root;
            m_root          = item;
            m_total_slice  += 1;
            m_used_bytes   += bytes;
            return & item[1];
        }

        template<class item_t>
        auto item_as() const {
            return [this](uxx length){
                return (item_t *)this->operator()(length * sizeof(item_t));
            };
        }

        void clear() const {
            while(m_root != nullptr){
                auto next   = m_root->next;
                inc::memory::default_free<void>(m_root, m_root->bytes);
                m_root      = next;
            }

            m_total_slice   = 0;
            m_used_bytes    = 0;
        }
    $
}

#endif

xexport_space(mixc::utils_temp_allocator::origin)